package de.bomzhi.mz.pflection.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.powerflasher.fdt.core.outermodel.IClassModel;
import com.powerflasher.fdt.core.outermodel.IFieldModel;
import com.powerflasher.fdt.core.outermodel.IFunctionModel;
import com.powerflasher.fdt.core.outermodel.IGetterModel;
import com.powerflasher.fdt.core.outermodel.IInterfaceModel;
import com.powerflasher.fdt.core.outermodel.IMasterModel;
import com.powerflasher.fdt.core.outermodel.IMemberNamespaceModel;
import com.powerflasher.fdt.core.outermodel.IMethodModel;
import com.powerflasher.fdt.core.outermodel.INamespaceModel;
import com.powerflasher.fdt.core.outermodel.IOuterModelElement;
import com.powerflasher.fdt.core.outermodel.ISetterModel;
import com.powerflasher.fdt.core.outermodel.IVariableModel;
import com.powerflasher.fdt.core.outermodel.MetaDataTagModel;
import com.powerflasher.fdt.core.outermodel.PackageModel;
import com.powerflasher.fdt.core.outermodel.SWCModel;
import com.powerflasher.fdt.core.outermodel.SourceFolderModel;
import com.powerflasher.fdt.core.outermodel.as3.IAS3LocalClassModel;
import com.powerflasher.fdt.core.outermodel.as3.IAS3LocalFunctionModel;
import com.powerflasher.fdt.core.outermodel.as3.IAS3LocalInterfaceModel;
import com.powerflasher.fdt.core.outermodel.as3.IAS3LocalNamespaceModel;
import com.powerflasher.fdt.core.outermodel.as3.IAS3LocalVariableModel;
import com.powerflasher.fdt.core.outermodel.binding.Binding;

public class PflectionValues {
	private Map<String, Set<Binding>> names = new HashMap<String, Set<Binding>>();
	public SetOfStrongTypedModels<SWCModel> SWCs = new SetOfStrongTypedModels<SWCModel>("SWCs");
	public SetOfStrongTypedModels<SourceFolderModel> sourceFolders = new SetOfStrongTypedModels<SourceFolderModel>("Source folders");
	public SetOfStrongTypedModels<PackageModel> packages = new SetOfStrongTypedModels<PackageModel>("Packages");
	public SetOfStrongTypedModels<IClassModel> classes = new SetOfStrongTypedModels<IClassModel>("Classes");
	public SetOfStrongTypedModels<IInterfaceModel> interfaces = new SetOfStrongTypedModels<IInterfaceModel>("Interface");
	public SetOfStrongTypedModels<IFunctionModel> functions = new SetOfStrongTypedModels<IFunctionModel>("Function");
	public SetOfStrongTypedModels<IVariableModel> variables = new SetOfStrongTypedModels<IVariableModel>("Variables");
	public SetOfStrongTypedModels<IVariableModel> constants = new SetOfStrongTypedModels<IVariableModel>("Constants");
	public SetOfStrongTypedModels<INamespaceModel> namespaces = new SetOfStrongTypedModels<INamespaceModel>("Namespaces");
	public SetOfStrongTypedModels<IAS3LocalClassModel> localClasses = new SetOfStrongTypedModels<IAS3LocalClassModel>("Local Classes");
	public SetOfStrongTypedModels<IAS3LocalInterfaceModel> localInterfaces = new SetOfStrongTypedModels<IAS3LocalInterfaceModel>("Local Interfaces");
	public SetOfStrongTypedModels<IAS3LocalFunctionModel> localFunctions = new SetOfStrongTypedModels<IAS3LocalFunctionModel>("Local Functions");
	public SetOfStrongTypedModels<IAS3LocalVariableModel> localVariables = new SetOfStrongTypedModels<IAS3LocalVariableModel>("Local Variables");
	public SetOfStrongTypedModels<IAS3LocalVariableModel> localConstants = new SetOfStrongTypedModels<IAS3LocalVariableModel>("Loacal Constants");
	public SetOfStrongTypedModels<IAS3LocalNamespaceModel> localNamespaces = new SetOfStrongTypedModels<IAS3LocalNamespaceModel>("Local Namespaces");
	public SetOfStrongTypedModels<IMethodModel> methods = new SetOfStrongTypedModels<IMethodModel>("Methods");
	public SetOfStrongTypedModels<IFunctionModel> eventListeners = new SetOfStrongTypedModels<IFunctionModel>("Event Listeners");
	public SetOfStrongTypedModels<IMethodModel> staticMethods = new SetOfStrongTypedModels<IMethodModel>("Static Methods");
	public SetOfStrongTypedModels<ISetterModel> setter = new SetOfStrongTypedModels<ISetterModel>("Setters");
	public SetOfStrongTypedModels<IGetterModel> getter = new SetOfStrongTypedModels<IGetterModel>("Getters");
	public SetOfStrongTypedModels<IFieldModel> field = new SetOfStrongTypedModels<IFieldModel>("Fields");
	public SetOfStrongTypedModels<IFieldModel> constantField = new SetOfStrongTypedModels<IFieldModel>("Constant fields");
	public SetOfStrongTypedModels<IMemberNamespaceModel> memberNamespaces = new SetOfStrongTypedModels<IMemberNamespaceModel>("Member namespaces");
	public SetOfStrongTypedModels<MetaDataTagModel> metaTags = new SetOfStrongTypedModels<MetaDataTagModel>("Metatags");
	private List<SetOfStrongTypedModels<IFunctionModel>> MLOCs = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IFunctionModel>> numberOfConditions = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IFunctionModel>> numberOfBlocks = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IFunctionModel>> numberOfFlowTerminations = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IFunctionModel>> numberOfInternalReferences = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IFunctionModel>> parameters = new ArrayList<SetOfStrongTypedModels<IFunctionModel>>(0);
	private List<SetOfStrongTypedModels<IInterfaceModel>> implemetntations = new ArrayList<SetOfStrongTypedModels<IInterfaceModel>>(0);
	private List<SetOfStrongTypedModels<IClassModel>> inheritanceDepth = new ArrayList<SetOfStrongTypedModels<IClassModel>>(0);
	private List<SetOfStrongTypedModels<IMasterModel>> outgoing = new ArrayList<SetOfStrongTypedModels<IMasterModel>>(0);
	private List<SetOfStrongTypedModels<IMasterModel>> incoming = new ArrayList<SetOfStrongTypedModels<IMasterModel>>(0);
	
	public static <T extends IOuterModelElement> void extendListToSizeWithDefault(List<SetOfStrongTypedModels<T>>list, int listSize, String defaultString, Class<T> clazz){
		if(list.size()<=listSize){
			for(int i = list.size(); i<=listSize;i++){
				SetOfStrongTypedModels<T>defaultValue = new SetOfStrongTypedModels<T>(defaultString);
				defaultValue.setIndex(i);
				list.add(i, defaultValue);
			}
		}
	}

	public void addParamValue(int numberOfParams, IFunctionModel element) {
		extendListToSizeWithDefault(parameters, numberOfParams, "Parameters in Function", IFunctionModel.class);
		parameters.get(numberOfParams).add(element);
	}
	
	public List<SetOfStrongTypedModels<IFunctionModel>> getParameters() {
		return parameters;
	}

	public void addMLOC(int numberMLOC, IFunctionModel element) {
		extendListToSizeWithDefault(MLOCs, numberMLOC, "MLOCs in Function", IFunctionModel.class);
		MLOCs.get(numberMLOC).add(element);
	}
	
	public List<SetOfStrongTypedModels<IFunctionModel>> getMLOCs() {
		return MLOCs;
	}
	
	public void addNumberOfConditions(int number,
			IFunctionModel element) {
		extendListToSizeWithDefault(numberOfConditions, number, "Conditions in Function", IFunctionModel.class);
		numberOfConditions.get(number).add(element);
	}
	
	public List<SetOfStrongTypedModels<IFunctionModel>> getNumberOfConditions() {
		return numberOfConditions;
	}

	public void addNumberOfBlocks(int number,
			IFunctionModel functionModel) {
		extendListToSizeWithDefault(numberOfBlocks, number, "Blocks in Function", IFunctionModel.class);
		numberOfBlocks.get(number).add(functionModel);
	}

	public List<SetOfStrongTypedModels<IFunctionModel>> getNumberOfBlocks() {
		return numberOfBlocks;
	}
	
	public void addNumberOfFlowTerminations(int number,
			IFunctionModel functionModel) {
		extendListToSizeWithDefault(numberOfFlowTerminations, number, "Terminations in Function", IFunctionModel.class);
		numberOfFlowTerminations.get(number).add(functionModel);
	}

	public List<SetOfStrongTypedModels<IFunctionModel>> getNumberOfFlowTerminations() {
		return numberOfFlowTerminations;
	}
	
	public void addNumberOfInternalReferences(int number,
			IFunctionModel functionModel) {
		extendListToSizeWithDefault(numberOfInternalReferences, number, "Internal refernces in Function", IFunctionModel.class);
		numberOfInternalReferences.get(number).add(functionModel);
	}
	
	public List<SetOfStrongTypedModels<IFunctionModel>> getNumberOfInternalReferences() {
		return numberOfInternalReferences;
	}

	public void addImplementationValue(int numberOfImplementations, IInterfaceModel element){
		extendListToSizeWithDefault(implemetntations, numberOfImplementations, "Interface implementations", IInterfaceModel.class);
		implemetntations.get(numberOfImplementations).add(element);
	}
	
	public List<SetOfStrongTypedModels<IInterfaceModel>> getImplemetntations() {
		return implemetntations;
	}

	public void addInheritansDepthValue(int depth, IClassModel element) {
		extendListToSizeWithDefault(inheritanceDepth, depth, "Super class", IClassModel.class);
		inheritanceDepth.get(depth).add(element);
	}
	
	public List<SetOfStrongTypedModels<IClassModel>> getInheritanceDepth() {
		return inheritanceDepth;
	}

	public void addOutgoing(int size, IMasterModel element) {
		extendListToSizeWithDefault(outgoing, size, "Outgoing References", IMasterModel.class);
		outgoing.get(size).add(element);
	}
	
	public List<SetOfStrongTypedModels<IMasterModel>> getOutgoing() {
		return outgoing;
	}

	public void addIncoming(int size, IMasterModel element) {
		extendListToSizeWithDefault(incoming, size, "Incoming References", IMasterModel.class);
		incoming.get(size).add(element);
	}
	
	public List<SetOfStrongTypedModels<IMasterModel>> getIncoming() {
		return incoming;
	}
	
	public void addName(IOuterModelElement element) {
		String name = element.getName();
		Set<Binding> elementsWithEqualName = names.get(name);
		if(elementsWithEqualName == null){
			elementsWithEqualName = new HashSet<Binding>();
			names.put(name, elementsWithEqualName);
		}
		elementsWithEqualName.add(element.getDeclarationBinding());
	}
	
	public Map<String, Set<Binding>> getNames() {
		return names;
	}
}
